package la.bbs558.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import la.bbs558.entity.*;
import la.bbs558.entity.dto.EchartsData;
import la.bbs558.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static la.bbs558.common.Constants.DAYS;
import static la.bbs558.common.Constants.YYYY_MM_DD;

/**
 * @author: Shanks
 * @date: 2024/1/12 14:53
 * @desc:
 */
@Service("statisticsManageService")
@Slf4j
public class StatisticsManageServiceImpl implements StatisticsManageService {

    @Resource
    private UserVisitStatisticsService userVisitStatisticsService;

    @Resource
    private UserVisitDayService userVisitDayService;

    @Resource
    private UserService userService;

    @Resource
    private UserDataService userDataService;
    @Resource
    private UserVisitRetentionService userVisitRetentionService;

    @Override
    public Map<String, Object> getTodayVisitCount() {
        DateTime todayDate = DateUtil.date();
        DateTime yesterdayDate = DateUtil.yesterday();
        UserVisitStatistics today = userVisitStatisticsService.lambdaQuery()
                .eq(UserVisitStatistics::getCreateDate, todayDate.toString(YYYY_MM_DD))
                .one();
        UserVisitStatistics yesterday = userVisitStatisticsService.lambdaQuery()
                .eq(UserVisitStatistics::getCreateDate, yesterdayDate.toString(YYYY_MM_DD))
                .one();
        if (today != null && yesterday != null) {
            // 今日访问量，相比昨日增长百分比
            int todayVisitCount = today.getVisitCnt();
            int yesterdayVisitCount = yesterday.getVisitCnt();
            double growthRate = (todayVisitCount - yesterdayVisitCount) / (yesterdayVisitCount * 1.0) * 100;
            return MapUtil.<String, Object>builder().put("todayVisitCount", todayVisitCount)
                    .put("growthRate", growthRate)
                    .build();
        } else if (today != null) {
            // 今日访问量，相比昨日增长百分比
            int todayVisitCount = today.getVisitCnt();
            return MapUtil.<String, Object>builder().put("todayVisitCount", todayVisitCount)
                    .put("growthRate", 100)
                    .build();
        } else if (yesterday != null) {
            // 今日访问量，相比昨日增长百分比
            return MapUtil.<String, Object>builder().put("todayVisitCount", 0)
                    .put("growthRate", -100)
                    .build();
        } else {
            // 今日访问量，相比昨日增长百分比
            return MapUtil.<String, Object>builder().put("todayVisitCount", 0)
                    .put("growthRate", 0)
                    .build();
        }
    }

    @Override
    public Map<String, Object> getTodayVisitUserCount() {
        DateTime todayDate = DateUtil.date();
        DateTime yesterdayDate = DateUtil.yesterday();
        Integer count = userVisitDayService.lambdaQuery()
                .eq(UserVisitDay::getCreateDate, todayDate.toString(YYYY_MM_DD))
                .count();
        Integer yesterdayCount = userVisitDayService.lambdaQuery()
                .eq(UserVisitDay::getCreateDate, yesterdayDate.toString(YYYY_MM_DD))
                .count();
        if (count != 0 && yesterdayCount != 0) {
            // 今日访问用户数，相比昨日增长百分比
            double growthRate = (count - yesterdayCount) / (yesterdayCount * 1.0) * 100;
            return MapUtil.<String, Object>builder().put("todayVisitUserCount", count)
                    .put("growthRate", growthRate)
                    .build();
        } else if (count != 0) {
            // 今日访问用户数，相比昨日增长百分比
            return MapUtil.<String, Object>builder().put("todayVisitUserCount", count)
                    .put("growthRate", 100)
                    .build();
        } else if (yesterdayCount != 0) {
            // 今日访问用户数，相比昨日增长百分比
            return MapUtil.<String, Object>builder().put("todayVisitUserCount", 0)
                    .put("growthRate", -100)
                    .build();
        } else {
            // 今日访问用户数，相比昨日增长百分比
            return MapUtil.<String, Object>builder().put("todayVisitUserCount", 0)
                    .put("growthRate", 0)
                    .build();
        }
    }

    @SneakyThrows
    @Override
    public EchartsData<String, Integer> todayVisitUserRetention() {
        EchartsData<String, Integer> echartsData = new EchartsData<>();
        //组装七天
        List<String> xData = rangeToList(-7).stream().map(dateTime -> DateUtil.format(dateTime, YYYY_MM_DD)).collect(Collectors.toList());
        List<List<Integer>> yData = new ArrayList<>();
        echartsData.setXData(xData);
        echartsData.setYData(yData);
        for (int i = 0, xDataSize = xData.size(); i < xDataSize; i++) {
            String dateTime = xData.get(i);
            List<Integer> yDataPart = new ArrayList<>();
            yData.add(yDataPart);
            for (int day : DAYS) {
                if(i == xDataSize - 1){
                    int size = userDataService.lambdaQuery()
                            .ge(UserData::getContinuousLoginDays, day)
                            .list().size();
                    yDataPart.add(size);
                }else {
                    Optional<UserVisitRetention> userVisitRetention = userVisitRetentionService.lambdaQuery()
                            .eq(UserVisitRetention::getCreateDate, dateTime)
                            .oneOpt();
                    if(userVisitRetention.isPresent()){
                        UserVisitRetention retention = userVisitRetention.get();
                        Field declaredField = retention.getClass().getDeclaredField("count" + day);
                        declaredField.setAccessible(true);
                        Object size = declaredField.get(retention);
                        yDataPart.add((Integer) size);
                    }else {
                        yDataPart.add(0);
                    }

                }

            }
        }
        return echartsData;
    }

    @Override
    public EchartsData<String, Integer> addUserCount() {
        List<DateTime> dateTimes = rangeToList(-7);
        List<String> dateStrList = dateTimes.stream().map(dateTime -> DateUtil.format(dateTime, YYYY_MM_DD)).collect(Collectors.toList());
        List<Integer> countList = new ArrayList<>();
        dateStrList.forEach(dateStr -> {
            Integer count = userService.lambdaQuery()
                    .between(User::getCreateTime, dateStr + " 00:00:00", dateStr + " 23:59:59")
                    .count();
            countList.add(count);
        });
        return new EchartsData<String, Integer>().setXData(dateStrList).setYData(Collections.singletonList(countList));
    }

    @Override
    public EchartsData<String, Integer> userVisitCount() {
        List<DateTime> dateTimes = rangeToList(-7);
        List<String> dateStrList = dateTimes.stream().map(dateTime -> DateUtil.format(dateTime, YYYY_MM_DD)).collect(Collectors.toList());
        List<Integer> countList = new ArrayList<>();
        dateStrList.forEach(dateStr -> {
            Integer count = userVisitStatisticsService.lambdaQuery()
                    .eq(UserVisitStatistics::getCreateDate, dateStr)
                    .last("limit 1")
                    .oneOpt().orElse(new UserVisitStatistics().setVisitCnt(0)).getVisitCnt();
            countList.add(count);
        });
        return new EchartsData<String, Integer>().setXData(dateStrList).setYData(Collections.singletonList(countList));
    }

    public List<DateTime> rangeToList(int offset) {
        DateTime date = DateUtil.date();
        return DateUtil.rangeToList(DateUtil.offsetDay(date, offset), date, DateField.DAY_OF_YEAR, 1);
    }

}
